package internal

import (
	"errors"
	"fmt"
	"github.com/shopspring/decimal"
	"gorm.io/gorm"
	"server/app/g1/internal/model"
	"server/libs/db"
	"server/libs/snowflake"
	"time"
)

type Account interface {
	// target 收账用户
	// amount 金额
	// outOrderSn 订单号
	// changetype 类型
	// remark 备注
	//
	Transfer(target int64, amount float64, changetype int32, outOrderSn int64, remark string) error
	TransferTx(_tx any, target int64, amount float64, changetype int32, outOrderSn int64, remark string) error
}

type AccountService struct {
}

func (this *AccountService) Transfer(target int64, amount float64, changetype int32, outOrderSn int64, remark string) error {
	return db.Mysql().Debug().Transaction(func(tx *gorm.DB) error {
		return this.TransferTx(tx, target, amount, changetype, outOrderSn, remark)
	})
}

func (this *AccountService) TransferTx(_tx any, target int64, amount float64, changetype int32, outOrderSn int64, remark string) (err error) {
	tx := _tx.(*gorm.DB)

	var userModel model.HomeUserInfo

reone:
	err = tx.
		Model(&model.HomeUserInfo{}).
		Select("id,username,amount").
		Where("id=?", target).
		First(&userModel).Error
	if err != nil {
		return errors.New("user is not found")
	}

	afterValue, _ := decimal.NewFromFloat(userModel.Amount).Add(decimal.NewFromFloat(amount)).Float64()

	changeId := snowflake.GetIdInt64()
	err = tx.Create(&model.UserAccountChangeModel{
		ID:             changeId,
		UserID:         target,
		BeforeAmount:   userModel.Amount,
		CurrentAmount:  amount,
		AfterAmount:    afterValue,
		StreamTypeDict: changetype,
		KeyID:          outOrderSn,
		ToAddress:      fmt.Sprintf("%d", target),
		CreatedAt:      time.Now(),
		UpdatedAt:      time.Now(),
	}).Error
	if err != nil {
		return err
	}

	//用户资金增加
	var resp = tx.Model(&model.HomeUserInfo{}).
		Where("id = ?", target).Where("amount=?", userModel.Amount).
		Update("amount", gorm.Expr("amount + ?", amount))
	if resp.Error != nil {
		return resp.Error
	}

	// 更新失败，被其他 task 更新了。从新尝试更新
	if resp.RowsAffected == 0 {
		goto reone
	}

	return nil
}
